package top.wilsonlv.jaguar.cloud.auth.extension.device;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetailsChecker;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import top.wilsonlv.jaguar.cloud.auth.sdk.token.DeviceAuthenticationToken;
import top.wilsonlv.jaguar.cloud.auth.security.UserDetailsServiceImpl;
import top.wilsonlv.jaguar.cloud.upms.sdk.vo.DeviceVO;
import top.wilsonlv.jaguar.commons.data.encryption.util.EncryptionUtil;
import top.wilsonlv.jaguar.security.model.SecurityUser;

/**
 * @author lvws
 * @since 2022/1/6
 */
@Slf4j
@Component
@RequiredArgsConstructor
@ConditionalOnProperty(prefix = "jaguar.auth", name = "device-auth-enable", havingValue = "true")
public class DeviceAuthenticationProvider implements AuthenticationProvider {

    private final UserDetailsServiceImpl userDetailsService;

    private final UserDetailsChecker userDetailsChecker;


    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        DeviceAuthenticationToken token = (DeviceAuthenticationToken) authentication;
        if (token.isAuthenticated()) {
            return token;
        }

        DeviceVO device = userDetailsService.loadDevice(token.getDeviceUid());
        if (device == null) {
            throw new UsernameNotFoundException("设备不存在");
        }
        if (!StringUtils.hasText(device.getDevicePublicKey())) {
            throw new UsernameNotFoundException("设备不可信");
        }

        String error = EncryptionUtil.checkRequestBySign(token.getTimestamp(), token.getNonce(), token.getSign(),
                token.getParams(), device.getDevicePublicKey());
        if (StringUtils.hasText(error)) {
            throw new UsernameNotFoundException(error);
        }

        SecurityUser securityUser = null;
        SecurityUser[] securityUsers = userDetailsService.loadUsersByDeviceUid(token.getDeviceUid(), (Long) token.getPrincipal());
        for (SecurityUser user : securityUsers) {
            if (token.getPrincipal().equals(user.getId())) {
                securityUser = user;
                break;
            }
        }
        if (securityUser == null) {
            throw new UsernameNotFoundException("设备未授权");
        }

        securityUser.setCredentialsNonExpired(true);

        // 检查账号状态
        userDetailsChecker.check(securityUser);

        DeviceAuthenticationToken authenticationToken = new DeviceAuthenticationToken(securityUser,
                token.getDeviceAuthType(), securityUser.getAuthorities());
        authenticationToken.setDetails(token.getDetails());
        return authenticationToken;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return DeviceAuthenticationToken.class.isAssignableFrom(authentication);
    }
}